{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<!-- DISABLE-FRONTMATTER-SECTIONS -->"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Speed Comparison"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Safetensors` is really fast. Let's compare it against `PyTorch` by loading [gpt2](https://huggingface.co/gpt2) weights. To run the [GPU benchmark](#gpu-benchmark), make sure your machine has GPU or you have selected `GPU runtime` if you are using Google Colab.\n",
    "\n",
    "Before you begin, make sure you have all the necessary libraries installed:\n",
    "\n",
    "```bash\n",
    "!pip install safetensors huggingface_hub torch\n",
    "```\n",
    "\n",
    "Let's start by importing all the packages that will be used:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import datetime\n",
    "from huggingface_hub import hf_hub_download\n",
    "from safetensors.torch import load_file\n",
    "import torch"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Download safetensors & torch weights for gpt2:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sf_filename = hf_hub_download(\"gpt2\", filename=\"model.safetensors\")\n",
    "pt_filename = hf_hub_download(\"gpt2\", filename=\"pytorch_model.bin\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### CPU benchmark"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Loaded safetensors 0:00:00.004015\n",
       "Loaded pytorch 0:00:00.307460\n",
       "on CPU, safetensors is faster than pytorch by: 76.6 X"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "start_st = datetime.datetime.now()\n",
    "weights = load_file(sf_filename, device=\"cpu\")\n",
    "load_time_st = datetime.datetime.now() - start_st\n",
    "print(f\"Loaded safetensors {load_time_st}\")\n",
    "\n",
    "start_pt = datetime.datetime.now()\n",
    "weights = torch.load(pt_filename, map_location=\"cpu\")\n",
    "load_time_pt = datetime.datetime.now() - start_pt\n",
    "print(f\"Loaded pytorch {load_time_pt}\")\n",
    "\n",
    "print(f\"on CPU, safetensors is faster than pytorch by: {load_time_pt/load_time_st:.1f} X\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This speedup is due to the fact that this library avoids unnecessary copies by mapping the file directly. It is actually possible to do on [pure pytorch](https://gist.github.com/Narsil/3edeec2669a5e94e4707aa0f901d2282).\n",
    "The currently shown speedup was gotten on:\n",
    "* OS: Ubuntu 18.04.6 LTS\n",
    "* CPU: Intel(R) Xeon(R) CPU @ 2.00GHz"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### GPU benchmark"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Loaded safetensors 0:00:00.165206\n",
       "Loaded pytorch 0:00:00.353889\n",
       "on GPU, safetensors is faster than pytorch by: 2.1 X"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# This is required because this feature hasn't been fully verified yet, but \n",
    "# it's been tested on many different environments\n",
    "os.environ[\"SAFETENSORS_FAST_GPU\"] = \"1\"\n",
    "\n",
    "# CUDA startup out of the measurement\n",
    "torch.zeros((2, 2)).cuda()\n",
    "\n",
    "start_st = datetime.datetime.now()\n",
    "weights = load_file(sf_filename, device=\"cuda:0\")\n",
    "load_time_st = datetime.datetime.now() - start_st\n",
    "print(f\"Loaded safetensors {load_time_st}\")\n",
    "\n",
    "start_pt = datetime.datetime.now()\n",
    "weights = torch.load(pt_filename, map_location=\"cuda:0\")\n",
    "load_time_pt = datetime.datetime.now() - start_pt\n",
    "print(f\"Loaded pytorch {load_time_pt}\")\n",
    "\n",
    "print(f\"on GPU, safetensors is faster than pytorch by: {load_time_pt/load_time_st:.1f} X\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The speedup works because this library is able to skip unecessary CPU allocations. It is unfortunately not replicable in pure pytorch as far as we know. The library works by memory mapping the file, creating the tensor empty with pytorch and calling `cudaMemcpy` directly to move the tensor directly on the GPU.\n",
    "The currently shown speedup was gotten on:\n",
    "* OS: Ubuntu 18.04.6 LTS.\n",
    "* GPU: Tesla T4\n",
    "* Driver Version: 460.32.03\n",
    "* CUDA Version: 11.2"
   ]
  }
 ],
 "metadata": {},
 "nbformat": 4,
 "nbformat_minor": 4
}
